package org.acghub.config;

import lombok.Getter;
import lombok.extern.slf4j.Slf4j;

import java.lang.reflect.Field;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @Desc
 * @Author miyuki4j
 * @Date 2025/7/24/星期四 17:40
 * @Version 1.0
 */
@Slf4j
public class ConfClassManager {

    private static final Map<String, Class<? extends AbstractConf>> CONF_NAME_2_CLASS = new ConcurrentHashMap<>(64);

    private static final Map<Class<? extends AbstractConf>, ConfClass> CONF_CLASS_2_FIELDS = new ConcurrentHashMap<>(64);

    public static <ConfType extends AbstractConf> void registerConfClass(Class<ConfType> confClazz) {
        ConfClass confClass = new ConfClass(confClazz);
        for (Field field : confClazz.getDeclaredFields()) {
            TableFieldAnno anno = field.getAnnotation(TableFieldAnno.class);
            if (anno != null) {
                ConfField confField = new ConfField(field, anno);
                confClass.addField(confField);
            }
        }
        confClass.parse();
        CONF_NAME_2_CLASS.put(confClazz.getName(), confClazz);
        CONF_CLASS_2_FIELDS.put(confClazz, confClass);
    }

    public static Class<? extends AbstractConf> registerConfClass(String confClassName) throws Exception {
        if (CONF_NAME_2_CLASS.containsKey(confClassName)) {
            return CONF_NAME_2_CLASS.get(confClassName);
        }
        Class<? extends AbstractConf> confClazz = (Class<? extends AbstractConf>) Class.forName(confClassName);
        registerConfClass(confClazz);
        return confClazz;
    }

    public static <ConfType extends AbstractConf> ConfClass getConfClass(Class<ConfType> confClazz) {
        return CONF_CLASS_2_FIELDS.get(confClazz);
    }


    @Getter
    public static final class ConfClass implements Iterable<ConfField>, TypeParseable {

        private final Class<? extends AbstractConf> clazz;

        private final Map<String, ConfField> name2FieldMap = new LinkedHashMap<>(16);

        public ConfClass(Class<? extends AbstractConf> clazz) {
            this.clazz = clazz;
        }

        @Override
        public Iterator<ConfField> iterator() {
            return name2FieldMap.values().iterator();
        }

        @Override
        public void parse() throws TypeParseException {
            for (ConfField field : this) {
                field.parse();
            }
        }

        public ConfField getField(String name) {
            return name2FieldMap.get(name);
        }

        public ConfField getField(int index) {
            for (ConfField confField : this) {
                if (confField.getAnno().index() == index) {
                    return confField;
                }
            }
            return null;
        }

        public void addField(ConfField confField) {
            name2FieldMap.put(confField.getAnno().name(), confField);
        }

    }

    @Getter
    public static final class ConfField implements TypeParseable {

        private final Field field;

        private final TableFieldAnno anno;

        private Type javaType;

        public ConfField(Field field, TableFieldAnno anno) {
            this.field = field;
            this.anno = anno;
            init();
        }


        private void init() {
            field.setAccessible(true);
        }

        @Override
        public void parse() throws TypeParseException {
            TableField tableField = new TableField(anno.index(), "", anno.name(), anno.type(), anno.delimiters());
            tableField.parse();
            javaType = tableField.getJavaType();
        }

        public void setValue(Object bean, Object value) throws Exception {
            field.set(bean, value);
        }

        public Object instance(String value) throws TypeInstanceException {
            return javaType.instance(value, anno.delimiters());
        }
    }
}
